package demoMod.gdxform.core;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.interfaces.*;
import demoMod.gdxform.ui.GMenuList;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class EventHooks implements InputProcessor {
    private static final ActionManager actionManager = new ActionManager();

    private Container<? extends Element> prepareToResizeContainer = null;

    private Element prepareToResizeElement = null;

    private Element currentFocusedElement = null;

    EventHooks() {
    }

    public void update() {
        actionManager.update();
    }

    @Override
    public boolean keyDown(int keyCode) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof KeyboardEventSubscriber) {
                if (((KeyboardEventSubscriber) container).keyDown(keyCode)) {
                    break;
                }
            }
        }
        return false;
    }

    @Override
    public boolean keyUp(int keyCode) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof KeyboardEventSubscriber) {
                if (((KeyboardEventSubscriber) container).keyUp(keyCode)) {
                    return false;
                }
            }
        }
        if (keyCode == Input.Keys.TAB) {
            List<Container<? extends Element>> containers = FormManager.getInstance().getContainerList().stream().filter(Container::visible).collect(Collectors.toList());
            int i;
            for (i=0;i<containers.size();i++) {
                Container<? extends Element> container = containers.get(i);
                if (container.isActivated()) {
                    if (!containers.get((i + 1) % containers.size()).hasFocus()) {
                        continue;
                    }
                    setCurrentFocusedElement(containers.get((i + 1) % containers.size()));
                    break;
                }
            }
            if (i >= containers.size() && !containers.isEmpty()) {
                List<Container<? extends Element>> tmp = containers.stream().filter(Element::hasFocus).collect(Collectors.toList());
                if (!tmp.isEmpty()) {
                    setCurrentFocusedElement(tmp.get(0));
                }
            }
        }
        return false;
    }

    @Override
    public boolean keyTyped(char key) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof KeyboardEventSubscriber) {
                if (((KeyboardEventSubscriber) container).keyTyped(key)) {
                    break;
                }
            }
        }
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) container).clickDown(screenX, screenY, button)) {
                    if (!(container instanceof GMenuList)) { //将点击事件继续传递给所有直属于容器管理器的菜单列表
                        for (int j=i-1;j>=0;j--) {
                            Container<? extends Element> menuList = containerList.get(j);
                            if (menuList instanceof GMenuList) {
                                ((GMenuList) menuList).clickDown(screenX, screenY, button);
                            }
                        }
                    }
                    return false;
                }
            }
        }
        skip:
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (button == Input.Buttons.LEFT && container.atBorder(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY())) {
                prepareToResizeContainer = container;
                break;
            }
            List<? extends Element> elements = container.getElements();
            Collections.reverse(elements);
            for (Element element : elements) {
                if (button == Input.Buttons.LEFT && element instanceof Border && ((Border) element).atBorder(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY())) {
                    prepareToResizeElement = element;
                    break skip;
                }
            }
        }
        if (prepareToResizeContainer != null && prepareToResizeContainer.isResizable()) {
            setCurrentFocusedElement(prepareToResizeContainer);
        } else if (prepareToResizeElement != null && prepareToResizeElement.isResizable()) {
            setCurrentFocusedElement(prepareToResizeElement);
        } else {
            setCurrentFocusedElement(null);
        }
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        prepareToResizeContainer = null;
        prepareToResizeElement = null;
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) container).clickUp(screenX, screenY, button)) {
                    break;
                }
            }
        }
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) container).mouseDragged(screenX, screenY)) {
                    break;
                }
            }
        }
        if (prepareToResizeContainer != null && prepareToResizeContainer.isResizable()) {
            prepareToResizeContainer.resize(Gdx.input.getDeltaX(), Gdx.input.getDeltaY(), false);
            return true;
        }
        if (prepareToResizeElement != null && prepareToResizeElement.isResizable()) {
            ((ResizeEventSubscriber) prepareToResizeElement).resize(Gdx.input.getDeltaX(), Gdx.input.getDeltaY(), false);
            return true;
        }
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) container).mouseMoved(screenX, screenY)) {
                    break;
                }
            }
        }
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        List<Container<? extends Element>> containerList = FormManager.getInstance().getContainerList();
        for (int i=containerList.size() - 1;i>=0;i--) {
            Container<? extends Element> container = containerList.get(i);
            if (container instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) container).scrolled(amount)) {
                    break;
                }
            }
        }
        return false;
    }

    public void setCurrentFocusedElement(Element element) {
        if (currentFocusedElement != null && currentFocusedElement != element) {
            currentFocusedElement.deactivate();
            Element parent = currentFocusedElement.getParent();
            while (parent != null) {
                parent.deactivate();
                parent = parent.getParent();
            }
        }
        if (currentFocusedElement != element) {
            if (element != null) {
                if (element.hasFocus()) {
                    element.activate();
                    this.currentFocusedElement = element;
                    Element parent = element.getParent();
                    while (parent != null) {
                        parent.activate();
                        parent = parent.getParent();
                    }
                }
            } else {
                currentFocusedElement = null;
            }
        }
    }

    public Element getCurrentFocusedElement() {
        return currentFocusedElement;
    }
}
